package com.gitee.base.security.shiro;

import com.gitee.base.modules.core.model.SysUser;
import com.gitee.base.modules.core.model.SysUserLoginLog;
import com.gitee.base.modules.core.service.ISysUserLoginLogService;
import com.gitee.base.modules.core.service.ISysUserService;
import com.gitee.base.security.permission.PermissionResolver;
import com.gitee.base.utils.Kit;
import com.gitee.base.utils.UserAgentParser;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.web.subject.WebSubject;
import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private ISysUserService sysUserService;
    @Autowired
    private ISysUserLoginLogService sysUserLoginLogService;

    @Autowired
    private PermissionResolver permissionResolver;

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken || token instanceof ShiroToken;
    }

    /**
     * 授权
     * @param principals
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        SysUser sysUser = (SysUser)principals.getPrimaryPrincipal();
        List<String> permissions = this.permissionResolver.permissionsByRoleIds(sysUser.getRoleIds());
        if(permissions!=null && !permissions.isEmpty()){
            simpleAuthorizationInfo.addStringPermissions(permissions.stream().flatMap(p-> Stream.of(p.split(","))).distinct().collect(Collectors.toList()));
        }
        return simpleAuthorizationInfo;
    }

    /**
     * 认证
     * @param token
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        SysUser sysUser = null;
        WebSubject webSubject = (WebSubject) SecurityUtils.getSubject();
        if(!webSubject.isAuthenticated()) {
            SysUserLoginLog.SysUserLoginLogBuilder sysUserLoginLogBuilder = SysUserLoginLog.builder().auto(false).time(LocalDateTime.now());

            if(token instanceof UsernamePasswordToken){
                //登录
                UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
                sysUser = this.sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername,usernamePasswordToken.getUsername()));
                if(sysUser!=null){
                    if(!DigestUtils.md5Hex(String.valueOf(usernamePasswordToken.getPassword())).equals(sysUser.getPassword())){
                        throw new UnknownAccountException("用户名或密码错误");
                    }
                }
            }
            if(token instanceof ShiroToken){
                //已登录，验证token
                ShiroToken shiroToken = (ShiroToken)token;
                String username = Kit.verifyToken(shiroToken.getCredentials().toString());
                sysUser = this.sysUserService.getOne(new LambdaQueryWrapper<SysUser>().eq(SysUser::getUsername,username));
                if(sysUser==null){
                    throw new UnknownAccountException("用户名或密码错误");
                }
                sysUserLoginLogBuilder.auto(true);
            }

            if(sysUser.getDeleted()){
                throw new LockedAccountException("帐号被锁定");
            }

            if(token instanceof UsernamePasswordToken){
                //记录登录日志
                HttpServletRequest request = (HttpServletRequest) ((WebSubject)SecurityUtils.getSubject()).getServletRequest();
                String uaString = request.getHeader("user-agent");
                sysUserLoginLogBuilder.userId(sysUser.getId()).browser(UserAgentParser.getBrowser(uaString)).os(UserAgentParser.getOS(uaString)).ip(Kit.getIp(request)).browserShort(UserAgentParser.getBrowserShort(uaString));
                this.sysUserLoginLogService.save(sysUserLoginLogBuilder.build());
            }
        }else{
            sysUser = (SysUser) webSubject.getPrincipal();
        }
        SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(sysUser,token.getCredentials(), ShiroRealm.class.getName());
        return simpleAuthenticationInfo;
    }
}
